﻿using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Project.Core.Config.Common.Lang;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace Config.Common.Utils {
    public class WxApi {

        /// <summary>
        /// 微信登录code换取token
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public static string GetSessionKey(string code) {
            string baseUrl = $@"https://api.weixin.qq.com/sns/jscode2session?appid={Const.APPID}&secret={Const.APPSECRET}&js_code={code}&grant_type=authorization_code";
            Debug.WriteLine("---微信登陆，通过code获取sessionkey");
            Debug.WriteLine("---baseUrl =" + baseUrl);
            string result;
            using (HttpClient http = new HttpClient()) {
                result = http.GetStringAsync(baseUrl).Result;
            }
            Debug.WriteLine("---拿到GET结果 =" + result);

            return result;
        }

        /// <summary>
        /// 微信下单api
        /// </summary>
        /// <param name="descr">商品描述</param>
        /// <param name="tradeNo">商户订单号</param>
        /// <param name="total">总金额</param>
        /// <param name="openid"></param>
        /// <returns></returns>
        public static async Task<string> JsapiOrder(string descr,string tradeNo,int total,string openid) {
            var data = new {
                appid = Const.APPID,
                mchid = Const.MCHID,
                description = descr,    //商品描述
                out_trade_no = tradeNo, //商户订单号
                //time_expire = DateTime.Now.AddMinutes(15).ToString("yyyy-MM-ddTHH:mm:ss+08:00"),  //交易结束时间
                notify_url = @"https://store.mylmj.top/wx/paycallback",  //通知地址
                amount = new {
                    total = total,      //总金额
                    currency = "CNY"    //货币类型
                },
                payer = new {
                    openid = openid
                }
            };

            string url = $@"https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
            string paramStr = JsonConvert.SerializeObject(data);
            var auth = BuildAuthAsync("POST", paramStr, new Uri(url).AbsolutePath);

            var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");

            using var client = new HttpClient();
            client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("WECHATPAY2-SHA256-RSA2048", auth);
            var response = await client.PostAsync(url, content);

            return await response.Content.ReadAsStringAsync();
        }

        /// <summary>
        /// 微信支付api
        /// </summary>
        /// <param name="prepayId"></param>
        /// <returns></returns>
        public static string Pay(string prepayId) {
            var appId = Const.APPID;
            var timeStamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            //var nonceStr = "5K8264ILTKCH16CQ2502SI8ZNMTM67VS";  //随机字符串
            string nonceStr = Path.GetRandomFileName();    //请求随机串
            var package = $"prepay_id={prepayId}";              //订单ID

            string message = $"{appId}\n{timeStamp}\n{nonceStr}\n{package}\n";
            string signature = RequestSign(message);    //签名
            //Debug.WriteLine(signature);

            var data = new {
                appId = appId,
                timeStamp = timeStamp,
                nonceStr = nonceStr,
                package = package,
                signType = "RSA",
                paySign = signature
            };

            return JsonConvert.SerializeObject(data);
        }

        /// <summary>
        /// 构造签名串
        /// </summary>
        /// <param name="method">HTTP请求方式（全大写）</param>
        /// <param name="body">API接口请求参数的json字符串</param>
        /// <param name="uri">API接口的相对路径</param>
        /// <returns></returns>
        protected static string BuildAuthAsync(string method, string body, string uri) {
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            string nonce = Path.GetRandomFileName();    //请求随机串
            //string nonce = "5K8264ILTKCH16CQ2502SI8ZNMTM67VS";

            string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            string signature = RequestSign(message);    //签名
            string serialNo = Const.SERIALNO;
            string mchid = Const.MCHID;
            return $"mchid=\"{mchid}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
        }

        /// <summary>
        /// 生成签名
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        protected static string RequestSign(string message) {
            //加载证书 API证书物理路径,API证书密码（默认是商户号）
            X509Certificate2 cer = new X509Certificate2(Const.APICERTPATH, Const.MCHID, X509KeyStorageFlags.Exportable);
            if (cer != null) {
                RSA rsa = cer.GetRSAPrivateKey();  //获取私钥
                //查看在不同平台上的具体类型
                byte[] data = Encoding.UTF8.GetBytes(message);
                return Convert.ToBase64String(rsa.SignData(data, System.Security.Cryptography.HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
            } else {
                return "";
            }
        }

        /// <summary>
        /// 退款申请
        /// </summary>
        /// <param name="tradeNo">商户订单号</param>
        /// <param name="refundNo">商户退款单号</param>
        /// <param name="reason">退款原因</param>
        /// <param name="refund">退款金额</param>
        /// <param name="total">原订单金额</param>
        /// <param name="goodsId">商户侧商品编码</param>
        /// <param name="unitPrice">商品单价</param>
        /// <param name="refundAmount">商品退款金额</param>
        /// <param name="refundQuantity">商品退货数量</param>
        /// <returns></returns>
        public static async Task<string> Refund(string tradeNo, string refundNo, string reason, int refund, int total, string goodsId, int unitPrice, int refundAmount, int refundQuantity) {
            var data = new {
                out_trade_no = tradeNo,//商户订单号
                out_refund_no = refundNo,//商户退款单号
                reason = reason, //退款原因
                notify_url = @"https://store.mylmj.top/wx/paycallback",  //通知地址
                //funds_account = "AVAILABLE",//可用余额账户
                amount = new {
                    refund = refund,    //退款金额
                    //@from = new[] {     //退款出资账户及金额
                    //    new { account = "AVAILABLE", amount = refund }
                    //},
                    total = total,      //总金额
                    currency = "CNY"    //货币类型
                },
                goods_detail = new[] {
                    new {
                        merchant_goods_id = goodsId,
                        unit_price = unitPrice,
                        refund_amount = refundAmount,
                        refund_quantity = refundQuantity
                    }
                }
            };

            string url = $@"https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
            string paramStr = JsonConvert.SerializeObject(data);
            var auth = BuildAuthAsync("POST", paramStr, new Uri(url).AbsolutePath);

            var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");

            using var client = new HttpClient();
            client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("WECHATPAY2-SHA256-RSA2048", auth);
            var response = await client.PostAsync(url, content);

            return await response.Content.ReadAsStringAsync();
        }
    }
}
